package com.cn.demo.service.impl;

import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 高级设备状态监控服务
 * 1. 每分钟记录设备心跳
 * 2. 检测异常设备（超时未下线）
 */
@Service
public class AdvancedDeviceMonitorService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final HashOperations<String, String, Long> hashOps;
    private static final String HEARTBEAT_KEY = "hert_rap";
    private static final String COUNTER_KEY = "hert_rap_counter";

    // 配置参数
    private static final long HEARTBEAT_INTERVAL = 30; // 30秒心跳间隔
    private static final long CHECK_INTERVAL = 60; // 60秒检查间隔
    private static final double THRESHOLD = 0.8; // 80%阈值

    // 记录可疑设备（第一次检测到超时但未下线的设备）
    private final Map<String, Long> suspiciousDevices = new ConcurrentHashMap<>();

    public AdvancedDeviceMonitorService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
        // 初始化HashOperations
        this.hashOps = redisTemplate.opsForHash();
    }

    /**
     * 每分钟执行一次的设备状态检查
     */
    @Scheduled(fixedRate = CHECK_INTERVAL, timeUnit = TimeUnit.SECONDS)
    public void checkDevicesAdvanced() {
        long currentTime = Instant.now().getEpochSecond();

        // 1. 获取当前心跳总数
        Long totalHeartbeats = redisTemplate.opsForValue().increment(COUNTER_KEY, 0);
        long expectedMinHeartbeats = (long) (2500 * (CHECK_INTERVAL / (double)HEARTBEAT_INTERVAL) * THRESHOLD);

        // 2. 获取所有设备心跳数据（生产环境建议用SCAN分批）
        Map<String, Long> allDevices = hashOps.entries(HEARTBEAT_KEY);

        // 3. 检查设备状态
        // 记录新的可疑设备和确认故障设备
        List<String> newSuspiciousDevices = new ArrayList<>();
        // 记录确认故障设备
        List<String> confirmedFaultDevices = new ArrayList<>();

        // 4. 遍历所有设备
        for (Map.Entry<String, Long> entry : allDevices.entrySet()) {
            String deviceSn = entry.getKey();
            long lastHeartbeat = entry.getValue();

            // 判断是否超时（超过1分钟无心跳）
            if (currentTime - lastHeartbeat > CHECK_INTERVAL) {
                if (suspiciousDevices.containsKey(deviceSn)) {
                    // 第二次检测到该设备超时
                    if (totalHeartbeats >= expectedMinHeartbeats) {
                        // 心跳总数正常，确认设备故障
                        confirmedFaultDevices.add(deviceSn);
                        suspiciousDevices.remove(deviceSn);
                    }
                    // 如果心跳总数仍低，保持可疑状态（可能是网络问题）
                } else {
                    // 第一次检测到超时
                    newSuspiciousDevices.add(deviceSn);
                }
            }
        }

        // 4. 处理网络波动情况
        if (totalHeartbeats < expectedMinHeartbeats) {
            handleNetworkFluctuation(totalHeartbeats, expectedMinHeartbeats);

            // 将本次检测到的新可疑设备加入监控列表
            for (String sn : newSuspiciousDevices) {
                suspiciousDevices.put(sn, currentTime);
            }
        } else {
            // 5. 处理确认故障的设备
            for (String sn : confirmedFaultDevices) {
                markDeviceAsFaulty(sn);
            }

            // 6. 处理新可疑设备（网络正常但设备超时）
            for (String sn : newSuspiciousDevices) {
                suspiciousDevices.put(sn, currentTime);
            }
        }

        // 7. 清理过期的可疑设备记录（超过2个检查周期）
        cleanupSuspiciousDevices(currentTime);
    }

    private void handleNetworkFluctuation(long actual, long expected) {
        double percentage = actual * 100.0 / expected;
        System.out.printf("网络波动告警: 心跳总数 %.0f 低于阈值 %.0f (%.1f%%)%n",
                (double)actual, (double)expected, percentage);

        // 如果是连续第二次检测到网络波动
        if (isContinuousNetworkIssue()) {
            System.out.println("严重告警: 持续网络问题，请立即检查!");
        }
    }

    private void markDeviceAsFaulty(String deviceSn) {
        System.out.println("设备确认故障: " + deviceSn);
        // 实现设备下线逻辑
        // 1. 从Redis移除
        hashOps.delete(HEARTBEAT_KEY, deviceSn);
        // 2. 通知相关系统
        // 3. 记录到数据库
    }

    private void cleanupSuspiciousDevices(long currentTime) {
        // 移除超过2个检查周期仍未被确认的记录
        suspiciousDevices.entrySet().removeIf(entry ->
                currentTime - entry.getValue() > CHECK_INTERVAL * 2
        );
    }

    private boolean isContinuousNetworkIssue() {
        // 实现连续网络问题的检测逻辑
        // 可以基于历史记录判断
        return false;
    }
}